﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GmSubFrame.h"
#include "GmMainWindow.h"
#include "UpdateApplyAndCancelGuisEvent.h"
#include "UpdateEditModeBorderEvent.h"
#include "IMainWindow.h"

// GcmpJournal 模块
#include "IJournalCommandData.h"
#include "JournalUtils.h"       ///// TODO:


// GcmpCommandAction 模块
#include "GcmpCommandState.h"


// GcmpUiView 模块
#include "IUiDocumentViewManager.h"
#include "IUiDocument.h"
#include "IUiView.h"


// GcmpDevService 模块
#include "IPublishConfig.h"
#include "CommandParameters.h"
#include "GbmpAssert.h"


// GcmpModel  模块
#include "IDocument.h"
#include "IModelView.h"
#include "IEditMode.h"
#include "IElementBasicInformation.h"


#include <QKeyEvent>
#include <QApplication>
#include "IApplication.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"





using namespace gcmp;

//////////////////////////////////////////////////////////////////////////
// 标记子窗口被Command自动关闭，而不是被用户手动关闭
class SubFrameAutoClosedFlag
{
    CANNOT_COPY_OR_ASSIGN(SubFrameAutoClosedFlag);
public:
    SubFrameAutoClosedFlag(bool bClosedByMainFrame = false)
    {
        m_bIsAutoClosed = true;
        m_bClosedByMainFrame = bClosedByMainFrame;
    }
    ~SubFrameAutoClosedFlag()
    {
        m_bIsAutoClosed = false;
        m_bClosedByMainFrame = false;
    }

    static bool IsAutoClosed() { return m_bIsAutoClosed; }
    static bool IsClosedByMainFrame() { return m_bClosedByMainFrame; }
private:
    // true表示将由程序代码进行关闭，将不记录日志
    static bool m_bIsAutoClosed;
    // true表示是否被主窗口的关闭事件而引起的被动关闭，将不提示保存
    static bool m_bClosedByMainFrame;
};
bool SubFrameAutoClosedFlag::m_bIsAutoClosed = false;
bool SubFrameAutoClosedFlag::m_bClosedByMainFrame = false;

// 窗口关闭还影响窗口激活，导出以便调用
bool IsSubFrameAutoClosed()
{
    return SubFrameAutoClosedFlag::IsAutoClosed();
}
//////////////////////////////////////////////////////////////////////////

GmSubFrame::GmSubFrame(int iUIDocID, QWidget *parent, Qt::WindowFlags flags)
    : QMdiSubWindow(parent, flags)
{
    setAttribute(Qt::WA_DeleteOnClose);
    m_iUIDocID = iUIDocID;

    auto status = connect(this, SIGNAL(windowStateChanged(Qt::WindowStates,Qt::WindowStates)), this, SLOT(OnWindowStateChanged(Qt::WindowStates,Qt::WindowStates)));
    GBMP_ASSERT(status);
}

GmSubFrame::~GmSubFrame()
{

}

bool GmSubFrame::CloseProgrammactially()
{
    SubFrameAutoClosedFlag autoClosed;

    bool ret = close();
    return ret;
}

bool GmSubFrame::CloseByMainFrameAutomatically()
{
    SubFrameAutoClosedFlag autoClosed(true);
    bool ret = close();    
    DBG_WARN_AND_RETURN_UNLESS(ret, false, L"父窗口关闭了，子窗口不可能关闭不成功！",L"GDMPLab",L"2024-03-30");

    return ret;
}

void GmSubFrame::closeEvent(QCloseEvent *event)
{

    const IUiView* pUIView = GetView();
    if (pUIView && !SubFrameAutoClosedFlag::IsAutoClosed())
    {
        // 由于SubFrame的Ui关闭操作不记录，关闭时要额外记录日志
        const IUiDocument* pUiDoc = pUIView->GetUiDocument();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDoc, L"pUiDoc为空",L"GDMPLab",L"2024-03-30");
        const IDocument* pDoc = pUiDoc->GetDbDocument();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

        OwnerPtr<gcmp::IJournalCommandData> opCommandData = IJournalCommandData::Create();
        DBG_WARN_AND_RETURN_VOID_UNLESS(opCommandData, L"IJournalCommandData::Create()返回空指针",L"GDMPLab",L"2024-03-30");
        gcmp::CommandParameters paramArray;
        IModelView *pModelView = pUIView->GetModelView();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pModelView, L"pModelView为空",L"GDMPLab",L"2024-03-30");
        IElementBasicInformation *pBasInfo = pModelView->GetBasicInformation();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pBasInfo, L"pBasInfo为空",L"GDMPLab",L"2024-03-30");
        paramArray[L"DocName"] = pDoc->GetName();
        paramArray[L"ModelViewName"] = pBasInfo->GetName();
        paramArray[L"ModelViewType"] = StringUtil::ToWString((int)pModelView->GetViewType());
        paramArray[L"UiViewTag"] = pUIView->GetTag();
        opCommandData->SetParameterArray(paramArray);
        JournalUtils::RecordViewClose(TransferOwnership(opCommandData));
    }

    if (pUIView && pUIView->IsValid())
    {
        IUiDocumentViewManager* pUiDocViewMgr = IUiDocumentViewManager::Get();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDocViewMgr != nullptr, L"pUiDocViewMgr不能为null",L"GDMPLab",L"2024-03-30");
        IUiDocument* pUIDoc = pUiDocViewMgr->GetUiDocumentByRuntimeId(m_iUIDocID);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pUIDoc != nullptr, L"pUIDoc不能为null",L"GDMPLab",L"2024-03-30");
        bool allowToCloseDocument = true;
        if (!SubFrameAutoClosedFlag::IsClosedByMainFrame() && 1 == pUIDoc->GetAllUiViews().size())
        {
            allowToCloseDocument = pUiDocViewMgr->CanUiDocumentClose(m_iUIDocID);
        }

        bool res = false;
        if (allowToCloseDocument)
        {
            res = pUiDocViewMgr->CloseUiView(GetView());
        }
        if (!res) {
            event->ignore();
            return;
        }
    }

    // 置空表示文档已关闭，OnWindowStateChanged不需要处理
    m_wpGmView = nullptr;

    //立即发射自定义信号,当前UIView失效
    emit NotifyCloseView(this);

    IMainWindow* pMainWnd = IMainWindow::GetMainWindow();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pMainWnd, L"pMainWnd是空指针",L"GDMPLab",L"2024-03-30");
    QMdiArea* pMDIArea = dynamic_cast<GmMainWindow*>(pMainWnd)->GetQMdiArea();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pMDIArea, L"pMDIArea是空指针",L"GDMPLab",L"2024-03-30");

    //QObject::disconnect(pMDIArea, SIGNAL(subWindowActivated(QMdiSubWindow *)), this, SLOT(OnWindowActivated(QMdiSubWindow *)));

    //从mdiArea移除当前窗口(触发mdiArea消息)
    QMdiSubWindow::closeEvent(event);
}

void GmSubFrame::moveEvent(QMoveEvent * pEvent)
{
    IMainWindow* pMainWnd = IMainWindow::GetMainWindow();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pMainWnd, L"pMainWnd是空指针",L"GDMPLab",L"2024-03-30");
    IMainWindowPrivate* pUIMainWnd = dynamic_cast<IMainWindowPrivate*>(pMainWnd);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUIMainWnd != nullptr, L"pUIMainWnd不能为null",L"GDMPLab",L"2024-03-30");
    pUIMainWnd->ResetApplyOrCancelGuiPosition();

    QMdiSubWindow::moveEvent(pEvent);
}

void GmSubFrame::resizeEvent(QResizeEvent * pEvent)
{
    IMainWindow* pMainWnd = IMainWindow::GetMainWindow();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pMainWnd, L"pMainWnd是空指针",L"GDMPLab",L"2024-03-30");
    IMainWindowPrivate* pUIMainWnd = dynamic_cast<IMainWindowPrivate*>(pMainWnd);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUIMainWnd != nullptr, L"pUIMainWnd不能为null",L"GDMPLab",L"2024-03-30");
    pUIMainWnd->ResetApplyOrCancelGuiPosition();

    QMdiSubWindow::resizeEvent(pEvent);
}

void GmSubFrame::OnViewClosed()
{
    m_wpGmView = nullptr;
    FYI(L"[测试] m_wpGmView = nullptr");
}

UInt64 GmSubFrame::GetId()
{
    return winId();
}

bool GmSubFrame::Activate()
{
    mdiArea()->setActiveSubWindow(this);
    return true;
}

bool GmSubFrame::Close()
{
    return CloseProgrammactially();
}

void GmSubFrame::SetView(IUiView* pGmView)
{
    m_wpGmView = pGmView;
    if (!m_wpGmView)
    {
        FYI(L"[测试] m_wpGmView = nullptr");
    }
    
#ifdef _GNUF_WIP_REFACTOR_UIDOC_UIVIEW_LOGIC_
    QWidget * pViewWidget(gcmp::UIView::castToQWidget(pGmView));
#else
    UInt64 id = pGmView->GetUiViewId();
    QWidget* pViewWidget = QWidget::find((WId)id);
#endif // !_GNUF_WIP_REFACTOR_UIDOC_UIVIEW_LOGIC_

    setWidget(pViewWidget);
    // 为了在位编辑的外框和SubFrame之间没有间隙，并且窗口可以拖动大小
    setStyleSheet("QWidget{padding:1px;}");
}

gcmp::IUiView *GmSubFrame::GetView()
{
    return m_wpGmView.Get();
}

void GmSubFrame::OnWindowStateChanged(Qt::WindowStates oldState, Qt::WindowStates newState)
{
    if (!isVisible())
    {
        return;
    }

    if (!IsInEditMode())
    {
        return;
    }

    DBG_WARN_AND_RETURN_VOID_UNLESS(m_wpGmView, L"m_wpGmView不能为null",L"GDMPLab",L"2024-03-30");
    IApplication::Get()->PostEvent(NEW_AS_OWNER_PTR(UpdateApplyAndCancelGuisEvent));
    IApplication::Get()->PostEvent(NEW_AS_OWNER_PTR(UpdateEditModeBorderEvent, m_wpGmView->GetId()));
}

bool GmSubFrame::OnWindowActivated()
{
    IUiDocumentViewManager* pUiDocViewMgr = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_UNLESS(pUiDocViewMgr != nullptr, false, L"pUiDocViewMgr不能为null",L"GDMPLab",L"2024-03-30");
    if (m_wpGmView && m_wpGmView->IsValid())
    {
        bool res = pUiDocViewMgr->ActivateUiView(GetView(), false);
        return res;
    }
    return false;
}

bool GmSubFrame::IsInEditMode()
{
    if (!GetView())
    {
        return false;
    }
    IUiDocumentViewManager* pUiDocViewMgr = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pUiDocViewMgr != nullptr, L"pUiDocViewMgr不能为null",L"GDMPLab",L"2024-03-30");
    IUiDocument* pUIDoc = pUiDocViewMgr->GetUiDocumentByRuntimeId(m_iUIDocID);
    if (!pUIDoc)// 可能是从关闭的地方调过来的，此时UiDocument可能已经删掉了
    {
        return false;
    }
    IDocument* pDoc = pUIDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"doc为空",L"GDMPLab",L"2024-03-30");
    if (pDoc == nullptr)
    {
        return false;
    }
    if (GcmpCommandState::IsInInPlaceEditMode())
    {
        return true;
    }
    if (IEditMode::GetTopActiveEditMode(pDoc))
    {
        return true;
    }
    return false;
}